package pay.utils;


import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * 分布式锁工具类
 */
@Component
public class DistributedLockUtil {

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 执行带有分布式锁的操作
     *
     * @param lockKey 锁的key
     * @param action  要执行的操作
     * @param <T>     返回值类型
     * @return 操作结果
     */
    public <T> T executeWithLock(String lockKey, Supplier<T> action) {
        return executeWithLock(lockKey, 10, 30, action);
    }

    /**
     * 执行带有分布式锁的操作（可自定义超时时间）
     *
     * @param lockKey      锁的key
     * @param waitTime     等待锁的最大时间（秒）
     * @param leaseTime    锁的持有时间（秒）
     * @param action       要执行的操作
     * @param <T>          返回值类型
     * @return 操作结果
     */
    public <T> T executeWithLock(String lockKey, long waitTime, long leaseTime, Supplier<T> action) {
        RLock lock = redissonClient.getLock(lockKey);
        boolean locked = false;
        try {
            // 尝试获取锁
            locked = lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
            if (locked) {
                // 执行业务操作
                return action.get();
            } else {
                throw new RuntimeException("获取分布式锁失败，lockKey: " + lockKey);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("获取分布式锁被中断", e);
        } finally {
            if (locked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 执行无返回值的分布式锁操作
     *
     * @param lockKey 锁的key
     * @param action  要执行的操作
     */
    public void executeWithLock(String lockKey, Runnable action) {
        executeWithLock(lockKey, 10, 30, () -> {
            action.run();
            return null;
        });
    }

    /**
     * 执行无返回值的分布式锁操作（可自定义超时时间）
     *
     * @param lockKey   锁的key
     * @param waitTime  等待锁的最大时间（秒）
     * @param leaseTime 锁的持有时间（秒）
     * @param action    要执行的操作
     */
    public void executeWithLock(String lockKey, long waitTime, long leaseTime, Runnable action) {
        executeWithLock(lockKey, waitTime, leaseTime, () -> {
            action.run();
            return null;
        });
    }

    /**
     * 直接获取锁对象（用于复杂场景）
     *
     * @param lockKey 锁的key
     * @return RLock 对象
     */
    public RLock getLock(String lockKey) {
        return redissonClient.getLock(lockKey);
    }
}